﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace QstkCore.DataAccess
{
    // http://ichart.finance.yahoo.com/table.csv?s=AAPL&a=08&b=7&c=1984&d=00&e=13&f=2013&g=d&ignore=.csv

    public class YahooDownloader
    {
        private readonly string SOURCE_DATA_PATH;
        private readonly string dataPath;
        private DateTime now = DateTime.Now;
        private int missCounter;

        public YahooDownloader()
        {
            SOURCE_DATA_PATH = Environment.GetEnvironmentVariable("QSDATA");

            dataPath = SOURCE_DATA_PATH + "\\Yahoo";
            now = DateTime.Now;

            missCounter = 0; // Counts how many symbols we could not get

            ServicePointManager.DefaultConnectionLimit = 80;
        }

        public void Download()
        {
            var symbols = ReadSymbols(SOURCE_DATA_PATH + "\\Symbols.csv");
            GetData(symbols);
        }

        private List<string> ReadSymbols(string symbolsFilePath)
        {
            var symbols = new List<string>();

            using (var fs = File.Open(symbolsFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            using (var bs = new BufferedStream(fs, 262144))
            using (var sr = new StreamReader(bs))
            {
                string line = sr.ReadLine();
                while (line != null)
                {
                    line = sr.ReadLine();
                    if (line == null) break;

                    symbols.Add(line);
                }
            }

            return symbols;
        }

        public void GetData(List<string> symbols)
        {
            Console.WriteLine("Downloading market data...");

            Stopwatch stopwatch = Stopwatch.StartNew();

            Parallel.ForEach(symbols, new ParallelOptions {MaxDegreeOfParallelism = 50}, DownloadFile);

            Console.WriteLine("All done. Got " + (symbols.Count - missCounter) + " stocks. Could not get " + missCounter +
                              " stocks.");

            stopwatch.Stop();
            Console.WriteLine("  Elapsed time: " + stopwatch.Elapsed);
        }

        public void DownloadFile(string symbol)
        {
            var symbolName = symbol;
            if (symbol[0] == '$')
                symbolName = '^' + symbol.Substring(1);

            Console.WriteLine("Getting " + symbolName);

            var url = "http://ichart.finance.yahoo.com/table.csv?";

            var urlParams = string.Format("a={0}&b={1}&c={2}&d={3}&e={4}&f={5}&s={6}&g=d&ignore=.csv",
                                          1, 1, 2000, now.Month, now.Day, now.Year, symbolName);

            url += urlParams;

            int i = 0;
            while(i < 3) // 3 Retries
            {
                try
                {
                    using (var client = new WebClient())
                    {
                            var myProxy = new WebProxy();
                            myProxy.IsBypassed(new Uri(url));
                            client.Proxy = myProxy;
                            client.DownloadFile(url, dataPath + "\\" + symbolName + ".csv");
                    }
                    break;
                }
                catch (WebException e)
                {
                    Debug.Print(e.Message);
                    i++;
                    Thread.Sleep(2000*i);
                }
                catch (Exception e)
                {
                    Debug.Print(e.Message);
                    i = 3;
                    break;
                }           
            }

            // Timedout or other unrecoverable error
            if (i == 3)
            {
                Interlocked.Increment(ref missCounter);
                Console.WriteLine("Unable to fetch data for stock: " + symbolName);
            }
        }
    }
}